#include "device.h"
#include "component.h"

/* 调试打印接口 */
#define EXTEND_KDS_LOG(format, ...)  __OSAL_LOG("[extend_kds.c] " C_YELLOW format C_NONE, ##__VA_ARGS__)


/* 定义虚拟硬件接口 */
#ifdef EXTEND_ITIC
#define EXTEND_KDS_VHWL				vUART_4
#else
#define EXTEND_KDS_VHWL				vUART_2
#endif
#define EXTEND_INT_VHWL				vPIN_I2


/* UART事件处理周期 */
#define EXTEND_KDS_EVT_PROC_CYCLE	(10)

/* UART事件 */
#define EVENT_EXTEND_KDS			(1 << 0)
#define EVENT_EXTEND_KDS_SEND_ACK   (1 << 1)

/* EXTEND_KDS环形接收缓存 */
#ifndef EXTEND_KDS_RB_RXBUF_LENGTH
#define EXTEND_KDS_RB_RXBUF_LENGTH 	(128)			   	//EXTEND_KDS 接收环形缓存长度
#endif

///////////// 定义协议解析层数据结构 /////////////////////////////////////////////////////////////////////////////////////////
#define PROTOCOL_CMD_PACKET_STX      0XF5   //命令包数据头
#define PROTOCOL_CONFRIM_PACKET_STX  0X5F   //确认包数据头
#define PROTOCOL_ACK_PACKET_STX      0X5F   //应答包数据头

#define PACK_TYPE_CONFRIM            0X00   //应答包类型：确认包
#define PACK_TYPE_ACK                0X01   //应答包类型：应答包

#define PROTOCOL_SEND_TIMES          3      //锁发送命令包的最大次数
#define PROTOCOL_RESEND_CMD_TIMEOUT  200    //锁重发命令包间隔时间ms
#define PROTOCOL_SEND_ACK_TIME_GAP   20     //锁发出多包ACK的间隔时间ms

#define PROTOCOL_RX_CMD_BUF_QTY      10     //接收的命令包缓存数量（最多连续接收10个命令包）


#define UART_TASK_QUEUE_LEN     	 10		//定义发送命令的最大数目
///////////// 串口通信协议：数据包结构 /////////////////////////////////////////////////////////////////////////////////////////
#pragma pack(1)
/* 协议头结构 */
typedef struct
{
	uint8_t stx;  //数据头
	uint16_t sum; //校验和
	uint8_t len;  //数据长度
}ProtocolDataHead_stu_t;

/* 命令包结构 */
typedef struct
{
	ProtocolDataHead_stu_t head;
	uint8_t cmd;
	uint8_t dataBuf[];//数据域长度不定
}CmdPacket_stu_t;

/* 确认包结构 */
typedef struct
{
	ProtocolDataHead_stu_t head;
	uint8_t confrim;
}ConfrimPacket_stu_t;

/* 应答包结构 */
typedef struct
{
	ProtocolDataHead_stu_t head;
	uint8_t cmd;
	uint8_t ret;
	uint8_t dataBuf[];//数据域长度不定
}AckPacket_stu_t;
#pragma pack()

//tx命令包结构
typedef struct 
{
	uint8_t  buffer[MAX_PACKAGE_LEN]; //发送缓存
	uint16_t  len;                     //数据长度
	uint32_t acktimeout;              //等待ACK的超时时间（为0：不需要ACK）
    extkds_send_cb_fun_t cb;            //发送命令回调（为NULL：不需要回调）
}uart_txcmd_packet_stu_t;

/* 命令包发送状态信息 */
static struct
{
    uart_txcmd_packet_stu_t data;     //数据
	uint32_t timeStamp;               //最后一次发送的时间戳
	uint8_t  cnt;                     //发送次数（可能重发）
	enum
	{                                 //当前发送的状态
		TX_STA_IDLE,                  //空闲
		TX_STA_WAIT_CONFRIM,          //等待模块回复确认包
		TX_STA_WAIT_ACK,              //等待模块回复应答包
	}status;
	RingBufferHandle_t tbHandle;
}CmdPacketTxInfo;

/* 命令包接收状态信息：记录蓝牙和Uart两个设备的发送状态 */
static struct
{
	uint8_t protocolBuf[MAX_PACKAGE_LEN];//协议解析缓存
	uint8_t protocolCount;               //协议解析计数变量
	RingBufferHandle_t rbHandle;
	ExtendKdsMsg_t *rx_msg;
	enum
	{ 
        RX_STA_IDLE,                        //空闲
        RX_STA_SEND_ACK,                    //正在发送多包ACK
    }status;
}CmdPacketRxInfo;

/* 定义发送缓存 */
static uint8_t uart_tx_buffer[MAX_PACKAGE_LEN] = {0};
static uint16_t tx_ctrl_flg=0; 
static uint16_t g_special_len = 0; //兼容0xDE指令，同一用这个变量做长度

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
  * @brief  打印HEX数据，最多只能打印32字节
  * @note
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  */
static void ExtKds_PrintfHexData(char *Msg,uint8_t *pData, uint16_t len)
{
	char *str_buffer = OSAL_Malloc(len * 3 + 1);
    if (str_buffer != NULL)
    {
        memset(str_buffer,0,len * 3 + 1);
        EXTEND_KDS_LOG("%s:%d(Bytes)\r\n", Msg, len);
        if (str_buffer != NULL)
        {
            for (int i=0; i<len; i++)
            {
                sprintf(&str_buffer[i*3], "%02X ", pData[i]);
            }
            EXTEND_KDS_LOG("%s\r\n\r\n", str_buffer);
        }
    }
	if (str_buffer) OSAL_Free(str_buffer);
}

/**
  * @brief  计算校验和
  * @note
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @return 成功返回校验和
  */
static uint16_t ExtKds_CalcCheckSum(uint8_t *pData, uint16_t len)
{
	uint16_t sum = 0;

	for (; len; len--)
	{
		sum += *pData++;
	}
	return sum;
}

/**
  * @brief  获取发送缓存区的状态
  * @note
  *
  * @return 缓存区为空返回0
  */
static uint8_t ExtKds_GetTxBufferStatus(void)
{
	return tx_ctrl_flg;
}

/**
  * @brief  加载待发送的数据
  * @note   将要发出的数据，填入发送缓存区
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @return 成功返回SUCCESS，失败返回ERROR
  */
static ErrorStatus ExtKds_LoadingDataToBeSent(uint8_t *pData, uint16_t len)
{
	uint8_t *pSendBuf = uart_tx_buffer;
	EXTEND_KDS_LOG("uart_tx_buffer[0]:%02X\r\n",pSendBuf[0]);
	if (tx_ctrl_flg == 0)
	{
		tx_ctrl_flg = len;
		memcpy(pSendBuf, pData, len);
		return SUCCESS;
	}
	EXTEND_KDS_LOG("Loading Tx data failed\r\n");
	return ERROR;
}

/**
  * @brief  处理发送缓存
  * @note   将发送缓存区的数据，通过串口发出，并处理Int控制逻辑
  *
  */
static void ExtKds_ProcessTxBuffer(void)
{
	uint8_t *pSendBuf = uart_tx_buffer;

	if (tx_ctrl_flg > 0)
	{	

		if (tx_ctrl_flg & 0X8000)
		{
			/* 调用硬件层write接口，发出数据 */
			ExtKds_PrintfHexData("Uart send packet",pSendBuf,  tx_ctrl_flg & 0X7FFF);
			#if defined(EXTEND_ITIC) && !defined(WIFI_TYPE_8266)
			Device_Write(EXTEND_INT_VHWL,NULL,0,0);
			Device_Write(EXTEND_KDS_VHWL, pSendBuf, tx_ctrl_flg & 0X7FFF, 0);
			Device_Write(EXTEND_INT_VHWL,NULL,0,1);
			Device_Write(EXTEND_INT_VHWL, NULL, 0, PIN_MODE_INPUT_PULLUP);
			#else
			Device_Write(EXTEND_KDS_VHWL, pSendBuf, tx_ctrl_flg & 0X7FFF, 0);
			#endif
			
			tx_ctrl_flg = 0;
		}
		else
		{
			/* 开始发数据，通知底层先发出唤醒信号 */
			#if defined(EXTEND_ITIC) && !defined(WIFI_TYPE_8266)
			{	static uint8_t time_cnt;

				if(time_cnt == 0)
				{	
					Device_Write(EXTEND_INT_VHWL, NULL, 0, PIN_MODE_OD_DRIVE);
					Device_Write(EXTEND_INT_VHWL,NULL,0,0);
				}
				else if(time_cnt>=6)
				{
					time_cnt=0XFF;
					Device_Write(EXTEND_INT_VHWL,NULL,0,1);
					tx_ctrl_flg |= 0X8000;
				}
				time_cnt++;	
			}
			#else
			tx_ctrl_flg |= 0X8000;
			#endif
		}
	}
}

/**
  * @brief  重发命令包，并处理超时逻辑
  *
  * @note   MCU发出命令包后，超时没有收到确认包，就重发
  */
static void ExtKds_ResendCmdPacket(void)
{
	uint8_t send_timeout_msg = 0;
	uint32_t currentTime = OSAL_GetTickCount();

	if (CmdPacketTxInfo.status == TX_STA_WAIT_CONFRIM)//等待确认包
	{
		if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp)  > PROTOCOL_RESEND_CMD_TIMEOUT)
		{
            EXTEND_KDS_LOG("wait confrim timeout\r\n");
			if (CmdPacketTxInfo.cnt >= PROTOCOL_SEND_TIMES)//ERR:等待确认包超时
			{
				send_timeout_msg = 1;
				CmdPacketTxInfo.status = TX_STA_IDLE;
				if(CmdPacketTxInfo.data.acktimeout == 60000)//配网指令
				{
					OSAL_SetTaskStatus(TASK_STA_NORMAL); //指纹流程开始：允许系统休眠
				}
			}
			else//重发（先判断发送缓存为空）
			{
				ExtKds_LoadingDataToBeSent(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
				CmdPacketTxInfo.timeStamp = currentTime;
				CmdPacketTxInfo.cnt++;
			}
		}
	}
	else if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK)//等待应答包
	{
        if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp) > CmdPacketTxInfo.data.acktimeout)//ERR:等待应答包超时
		{
            EXTEND_KDS_LOG("wait ack timeout\r\n");
			send_timeout_msg = 1;
			CmdPacketTxInfo.status = TX_STA_IDLE;
			if(CmdPacketTxInfo.data.acktimeout == 60000)//配网指令
			{
				OSAL_SetTaskStatus(TASK_STA_NORMAL); //指纹流程开始：允许系统休眠
			}
		}
	}

	/* exec timeout callback */
    if(send_timeout_msg)
    {
        ExtendKdsMsg_t *tmp = (ExtendKdsMsg_t *)OSAL_Malloc(sizeof(ExtendKdsMsg_t));
        if(tmp)
        {
            tmp->msgType = EXT_EXEC_CB;
            tmp->cb = CmdPacketTxInfo.data.cb;
            tmp->cmd = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->cmd;
            tmp->len = 0;
            OSAL_MessagePublish(tmp, sizeof(ExtendKdsMsg_t) + tmp->len);
			OSAL_Free(tmp);
        }
        CmdPacketTxInfo.data.cb = NULL;
    }
}

/**
  * @brief  处理接收的确认包
  * @note
  *
  * @param  pConfrimPacket：确认包数据指针
  */
static void ExtKds_ProcessRxConfrimPacket(ConfrimPacket_stu_t *pConfrimPacket)
{
	if (CmdPacketTxInfo.status == TX_STA_WAIT_CONFRIM)
	{
		if (CmdPacketTxInfo.data.acktimeout > 0)//需要等待应答包
		{
			CmdPacketTxInfo.status = TX_STA_WAIT_ACK;
			CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
		}
		else
		{
			CmdPacketTxInfo.status = TX_STA_IDLE;
			ExtendKdsMsg_t *tmp = (ExtendKdsMsg_t *)OSAL_Malloc(sizeof(ExtendKdsMsg_t));
			if(tmp)
			{
				tmp->msgType = EXT_EXEC_CB;
				tmp->cb = CmdPacketTxInfo.data.cb;
				tmp->cmd = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->cmd;
				tmp->len = 1;
				memcpy(((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->dataBuf, &pConfrimPacket->confrim, tmp->len);
				OSAL_MessagePublish(tmp, sizeof(ExtendKdsMsg_t) + tmp->len);
				OSAL_Free(tmp);
			}
		}
	}
}

/**
  * @brief  处理接收的应答包
  * @note
  *
  * @param  pAckPacket：应答包数据指针
  */
static void ExtKds_ProcessRxAckPacket(AckPacket_stu_t *pAckPacket)
{
	if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK && pAckPacket->cmd == CmdPacketTxInfo.data.buffer[sizeof(ProtocolDataHead_stu_t)])
	{
		if(pAckPacket->cmd == 0xB0)//配网指令
		{
			OSAL_SetTaskStatus(TASK_STA_NORMAL); //指纹流程开始：允许系统休眠
		}
		CmdPacketTxInfo.status = TX_STA_IDLE;
		ExtendKdsMsg_t *tmp = (ExtendKdsMsg_t *)OSAL_Malloc(sizeof(ExtendKdsMsg_t) + g_special_len - 1);
		if(tmp)
		{
			tmp->msgType = EXT_EXEC_CB;
			tmp->cb = CmdPacketTxInfo.data.cb;
			tmp->cmd = ((CmdPacket_stu_t *)CmdPacketTxInfo.data.buffer)->cmd;
			tmp->len = g_special_len - 1;
			memcpy(&tmp->data, &pAckPacket->ret, tmp->len);
			OSAL_MessagePublish(tmp, sizeof(ExtendKdsMsg_t) + tmp->len);
			OSAL_Free(tmp);
		}
	}
}


/**
  * @brief  发出确认包
  *
  * @note   MCU收到无线模组发过来命令后，通过调用该函数给模组回复确认包
  */
static void ExtKds_SendConfrimPacket(uint8_t ack)
{
	ConfrimPacket_stu_t packet;
	packet.head.stx = PROTOCOL_CONFRIM_PACKET_STX;
	packet.head.len = 1;
	packet.confrim = ack;
	packet.head.sum = ExtKds_CalcCheckSum((uint8_t*)&(packet.confrim), packet.head.len);
	Device_Write(EXTEND_KDS_VHWL, &packet, sizeof(ConfrimPacket_stu_t), 0);
	ExtKds_PrintfHexData("ExtKds Send Confrim",(uint8_t *)&packet,sizeof(ConfrimPacket_stu_t));
}

static ErrorStatus ExtKds_SendAck(uint8_t cmd, void *data, uint16_t len)
{
	uint16_t checksum_len = 0;
    ErrorStatus res = ERROR;
    CmdPacket_stu_t *sdata = (CmdPacket_stu_t *)OSAL_Malloc(sizeof(CmdPacket_stu_t) + len); 
    sdata->head.stx = PROTOCOL_ACK_PACKET_STX;

	//升级赛普拉斯wifi锁，固定包1035个长度，这里用0表示
	if ((0x92 == cmd) && (1040 == len))
	{
		sdata->head.len = 0;
		checksum_len = len + 1;
	}
	else
	{
		sdata->head.len = (len + 1)&0XFF;
		checksum_len = sdata->head.len;
	}

    sdata->cmd = cmd;
    memcpy(sdata->dataBuf,data,len);
    
    if (sdata->dataBuf[0] == 0x00 || sdata->dataBuf[0] == 0x01)//需要在次发送ACK
    {
        sdata->dataBuf[0] = 0x80;
		if (CmdPacketRxInfo.rx_msg) CmdPacketRxInfo.rx_msg->times++;
        OSAL_EventSingleCreate(COMP_EXTEND_KDS, EVENT_EXTEND_KDS_SEND_ACK, PROTOCOL_SEND_ACK_TIME_GAP, EVT_PRIORITY_MEDIUM);
    }
    else
    {
        if (CmdPacketRxInfo.rx_msg)
        {
            OSAL_Free(CmdPacketRxInfo.rx_msg);
            CmdPacketRxInfo.rx_msg = NULL;
        }  
        CmdPacketRxInfo.status = RX_STA_IDLE; 
    }

    if(sdata->cmd == 0xDE)
	{
		sdata->dataBuf[1] = ((len + 1)>>8)&0XFF;
		sdata->head.sum = ExtKds_CalcCheckSum(&sdata->cmd,(len + 1));
	}
	else
	{
		sdata->head.sum = ExtKds_CalcCheckSum(&sdata->cmd, checksum_len);
	}
	

	if (Device_Write(EXTEND_KDS_VHWL, sdata, sizeof(CmdPacket_stu_t) + len, 0) == 0)
	{
		res = SUCCESS;
		ExtKds_PrintfHexData("ExtKds Send Ack",(uint8_t *)sdata,sizeof(CmdPacket_stu_t) + len);
	}
    if (sdata) OSAL_Free(sdata);
    return res;
}

/**
  * @brief  处理接收的命令包
  * @note
  *
  * @param  pCmdPacket：数据包指针
  */
static void ExtKds_ProcessRxCmdPacket(CmdPacket_stu_t *pCmdPacket)
{
	uint8_t len = pCmdPacket->head.len;
	static uint8_t last_len = 0; //用来保存上一次的长度，比如收到0xB0没有进行ACK，下次收到更长的指令就内存溢出了
	EXTEND_KDS_LOG("Recv packet, cmd: 0x%02X\r\n", pCmdPacket->cmd);
	ExtKds_PrintfHexData("rev data",(uint8_t *)pCmdPacket,len + 4);
	if (CmdPacketRxInfo.rx_msg == NULL) 
	{
		last_len = len;
		CmdPacketRxInfo.rx_msg = (ExtendKdsMsg_t *)OSAL_Malloc(sizeof(ExtendKdsMsg_t) + len);//多包ACK结束时需要释放
	}
	else
	{
		if(last_len < len) //上次申请的长度不够
		{
			EXTEND_KDS_LOG("last_len: %d, len: %d\r\n", last_len, len);
			last_len = len;
			OSAL_Free(CmdPacketRxInfo.rx_msg);
			CmdPacketRxInfo.rx_msg = (ExtendKdsMsg_t *)OSAL_Malloc(sizeof(ExtendKdsMsg_t) + len);
		}
	}
	
	if (CmdPacketRxInfo.rx_msg != NULL)
	{
		CmdPacketRxInfo.rx_msg->msgType = EXT_RECV_CMD_PACKET;
		CmdPacketRxInfo.rx_msg->cmd = pCmdPacket->cmd;
		CmdPacketRxInfo.rx_msg->len = pCmdPacket->head.len - 1;//减去CMD命令字节
		CmdPacketRxInfo.rx_msg->times = 0;
		memcpy(CmdPacketRxInfo.rx_msg->data, &pCmdPacket->dataBuf, CmdPacketRxInfo.rx_msg->len);
		OSAL_MessagePublish(CmdPacketRxInfo.rx_msg, sizeof(ExtendKdsMsg_t) + CmdPacketRxInfo.rx_msg->len);
		if (0xB0 != CmdPacketRxInfo.rx_msg->cmd)
		{
			CmdPacketRxInfo.status = RX_STA_SEND_ACK;
		}
	}
	else
	{
		ExtKds_SendConfrimPacket(0x81);
		return;
	}
	
	/* 发出确认包 */
	ExtKds_SendConfrimPacket(0x80);
}

/**
  * @brief  解析接收的数据包
  * @note
  *
  * @param  pData：数据包地址
  */
static void ExtKds_ParseRxPacket(uint8_t *pData)
{
	ProtocolDataHead_stu_t *pPacketHead = (ProtocolDataHead_stu_t *)pData;

    if (pData == NULL)
    {
        return;
    }

	if (pPacketHead->stx == PROTOCOL_CMD_PACKET_STX)
	{
		/* 处理接收的命令包 */
		ExtKds_ProcessRxCmdPacket((CmdPacket_stu_t *)pData);
	}
	else if (pPacketHead->len == 1)
	{
		/* 处理接收的确认包 */
		ExtKds_ProcessRxConfrimPacket((ConfrimPacket_stu_t *)pData);
	}
	else
	{
		/* 处理接收应答包 */
		ExtKds_ProcessRxAckPacket((AckPacket_stu_t *)pData);
	}
}

/**
  * @brief  从底层环形缓存获取一包数据并解析
  *
  * @note   底层驱动收到数据，会暂存在环形缓存区
  *
  * @return 返回解析后的数据包地址，解析失败返回NULL
  */
static uint8_t *ExtKds_GetOnePacket(void)
{
	static uint8_t getPacketTimeoutCnt = 0;
	uint8_t tmpData = 0;
	uint16_t packetLen;
	uint8_t flag = 0; //长度特殊处理flag

	if (OSAL_RingBufferRead(CmdPacketRxInfo.rbHandle, &tmpData) == 0)
	{
		/* 连续3次没有读取到数据（30ms） */
		if (++getPacketTimeoutCnt >= 3)
		{
			getPacketTimeoutCnt = 0;
			CmdPacketRxInfo.protocolCount = 0;//清0解析计数
		}
		return NULL;
	}
	getPacketTimeoutCnt = 0;

	uint16_t *pCnt = (uint16_t *)&(CmdPacketRxInfo.protocolCount);  //解析计数
	uint8_t *protocolBuff = CmdPacketRxInfo.protocolBuf; 			//解析缓存
	do
	{
		if (*pCnt == 0)
		{
			if (tmpData == PROTOCOL_CMD_PACKET_STX       //命令帧
			 || tmpData == PROTOCOL_CONFRIM_PACKET_STX   //确认帧
			 || tmpData == PROTOCOL_ACK_PACKET_STX)      //应答帧
			{
				protocolBuff[0] = tmpData;
				*pCnt = 1;
			}
		}
		else if (*pCnt > 0)     //包头通过后才开始解析数据
		{
			protocolBuff[*pCnt] = tmpData;
			*pCnt = *pCnt + 1;
			if (*pCnt > 4)
			{
				ProtocolDataHead_stu_t *pPacketHead = (ProtocolDataHead_stu_t *)protocolBuff;
				
				if(0 == flag)
				{
					packetLen = pPacketHead->len + 4;
					if (*pCnt >= 7) 
					{
						//0xDE指令长度特殊处理
						if ((protocolBuff[6] > 0) && (0xDE == protocolBuff[4]))
						{
							flag = 1;
							packetLen = protocolBuff[6] * 256 + pPacketHead->len + 4;
						}
					}
				}
				else
				{
					packetLen = protocolBuff[6] * 256 + pPacketHead->len + 4;
				}

				if (*pCnt >= MAX_PACKAGE_LEN || packetLen == *pCnt)
				{
					if (packetLen == *pCnt)
					{
						if ( pPacketHead->sum == ExtKds_CalcCheckSum(protocolBuff + 4, packetLen - 4) )
						{
							// ExtKds_PrintfHexData("Uart Rx",protocolBuff, packetLen);
							*pCnt = 0;
							g_special_len = packetLen - 4;
							return protocolBuff;//接收完成
						}
						else
						{
							ExtKds_PrintfHexData("Uart Rx CRC ERR",protocolBuff, packetLen);
						}
					}
					*pCnt = 0;
					return NULL;
				}
			}
		}
	} while(OSAL_RingBufferRead(CmdPacketRxInfo.rbHandle, &tmpData));//while ( uart_hal_recv_data(&tmpData, 1, uart_dev_active,0) != 0 );
	return NULL;
}

/**
  * @brief  Uart任务 通信协议处理
  *
  * @note   该函数会每间隔10ms执行一次
  */
static void ExtKds_ProtocolPro(void)
{
    if (ExtKds_GetTxBufferStatus() != 0)
    {
        ExtKds_ProcessTxBuffer();      //处理发送缓存中的数据
    }
    else
    {
        ExtKds_ParseRxPacket( ExtKds_GetOnePacket() );//解析数据
        ExtKds_ResendCmdPacket();      //重发命令包
    }
}

/**
  * @brief  判断协议层是否为空闲状态
  * @note
  *
  * @return 空闲：返回SUCCESS， 正忙：返回ERROR
  */
static ErrorStatus ExtKds_IsProtocolIdle(void)
{
	/* 当前没有发出命令、发送缓存为空、接收的命令也处理完成了，才能发出新命令 */
	if ( CmdPacketTxInfo.status == TX_STA_IDLE && ExtKds_GetTxBufferStatus() == 0 && CmdPacketRxInfo.status == RX_STA_IDLE)
	{
		return SUCCESS;
	}
	return ERROR;
}

/**
  * @brief  Uart任务 协议层初始化
  *
  * @note
  */
static void ExtKds_ProtocolInit(void)
{
	CmdPacketTxInfo.status = TX_STA_IDLE;
	CmdPacketTxInfo.cnt = 0;
	CmdPacketRxInfo.status = RX_STA_IDLE;
	CmdPacketRxInfo.rx_msg = NULL;
	memset(CmdPacketRxInfo.protocolBuf, 0, sizeof(CmdPacketRxInfo.protocolBuf));
	CmdPacketRxInfo.protocolCount = 0;
}

//处理TX队列
static void ExtKds_ProcessTxQueue(void)
{
    uart_txcmd_packet_stu_t txcmd_packet = {0};
    
    if (ExtKds_IsProtocolIdle() != SUCCESS)
    {
        return;
    }
	if (OSAL_RingBufferRead(CmdPacketTxInfo.tbHandle, &txcmd_packet) != SUCCESS)
	{
		return;
	}
    CmdPacketTxInfo.data = txcmd_packet;
    CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();
    CmdPacketTxInfo.cnt = 1;
    CmdPacketTxInfo.status = TX_STA_WAIT_CONFRIM;

    ExtKds_LoadingDataToBeSent(CmdPacketTxInfo.data.buffer, CmdPacketTxInfo.data.len);
}

/**
  * @brief  串口接收回调
  * 
  * @return 
  */
static void ExtKds_Receivecb(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
	uint32_t i = 0;
	uint8_t *p = (uint8_t *)data;

	/* 收到的数据写入缓存 */
	for (i = 0; i < len; i++)
	{
		OSAL_RingBufferWrite(CmdPacketRxInfo.rbHandle, p + i);
	}
}

static ErrorStatus ExtendKds_ProcessMbox(uint8_t *msg)
{
    ExtendKdsMsg_t *temp = (ExtendKdsMsg_t *)msg;
	uint8_t cmd = temp->cmd;
	uint16_t len = temp->len;
	extkds_send_cb_fun_t cb = temp->cb;
	uint8_t *data = temp->data;
	uint32_t temp_baud = 0;
	ErrorStatus res = ERROR;
    uart_txcmd_packet_stu_t *send_packer = NULL;
	CmdPacket_stu_t *sdata;
	
	if (temp->msgType == EXT_SET_BAUD)
	{
		temp_baud |= temp->data[0];
		temp_baud |= temp->data[1] << 8;
		temp_baud |= temp->data[2] << 16;
		temp_baud |= temp->data[3] << 24;
		Device_SetUartBaudrate(EXTEND_KDS_VHWL, temp_baud);
	}
	else
	{
		EXTEND_KDS_LOG("ExtendKds_ProcessMbox, cmd: %02x, len: %d, cb: %p\r\n", cmd, len, cb);
		
		if (cb == NULL)//发送ACK
		{
			res = ExtKds_SendAck(cmd,data,len); 
			goto exit;
		}
		send_packer = (uart_txcmd_packet_stu_t *)OSAL_Malloc(sizeof(uart_txcmd_packet_stu_t));
		sdata = (CmdPacket_stu_t *)send_packer->buffer;
		sdata->head.stx = PROTOCOL_CMD_PACKET_STX;
		sdata->head.len = len + 1;
		sdata->cmd = cmd; 
		memcpy(sdata->dataBuf,data,len);
		sdata->head.sum = ExtKds_CalcCheckSum(&sdata->cmd,sdata->head.len);
		send_packer->len = sizeof(CmdPacket_stu_t) + len;
		send_packer->cb = cb;
		if(cmd == 0xB0)//配网命令
		{
			send_packer->acktimeout = 60000;
			OSAL_SetTaskStatus(TASK_STA_ACTIVE); //扩展模块流程开始：禁止系统休眠
		}
		else
		{
			send_packer->acktimeout = PROTOCOL_RESEND_CMD_TIMEOUT;
		}
		

		if (CmdPacketTxInfo.tbHandle != NULL)
		{
			if (OSAL_RingBufferWrite(CmdPacketTxInfo.tbHandle,send_packer) == SUCCESS)
			{
				res = SUCCESS;
			}  
		}
	}
    
 exit:  
    if (send_packer) OSAL_Free(send_packer);
    return res; 
}

/**
  * @brief  UART任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t ExtKds_Task(uint32_t event)
{
	static uint8_t uart_init_flag;
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		if(uart_init_flag == 0)
		{
			/* 创建RX环形缓存 */
			CmdPacketRxInfo.rbHandle = OSAL_RingBufferCreate(EXTEND_KDS_RB_RXBUF_LENGTH, 1);
			/* 创建TX环形缓存 */
			CmdPacketTxInfo.tbHandle = OSAL_RingBufferCreate(5, sizeof(uart_txcmd_packet_stu_t));
			/* 注册串口接收回调 */
			Device_RegisteredCB(EXTEND_KDS_VHWL, ExtKds_Receivecb);
			/* 初始化UART协议层 */
			ExtKds_ProtocolInit();
			uart_init_flag = 1;
		}
		OSAL_EventRepeatCreate(COMP_EXTEND_KDS, EVENT_EXTEND_KDS, EXTEND_KDS_EVT_PROC_CYCLE, EVT_PRIORITY_MEDIUM);
		EXTEND_KDS_LOG("ExtKds_Task start\r\n");
        Device_Enable(EXTEND_KDS_VHWL);
		return ( event ^ EVENT_SYS_START );
	}

	/* 串口处理事件 */
	if (event & EVENT_EXTEND_KDS)
	{
		ExtKds_ProtocolPro();
		ExtKds_ProcessTxQueue();
		return ( event ^ EVENT_EXTEND_KDS );
	}

	if (event & EVENT_EXTEND_KDS_SEND_ACK)//多个ACK包用到的
    {
        if (CmdPacketRxInfo.rx_msg) 
        {
            if (OSAL_MessagePublish(CmdPacketRxInfo.rx_msg, sizeof(ExtendKdsMsg_t) + CmdPacketRxInfo.rx_msg->len) != SUCCESS)
            {
                EXTEND_KDS_LOG("OSAL_MessagePublish error\r\n");  
            }
        }
        return ( event ^ EVENT_EXTEND_KDS_SEND_ACK );   
    }

	if (event & EVENT_SYS_MBOX)
    {
        uint8_t buffer[MAX_PACKAGE_LEN + 10] = {0};
        while (OSAL_MboxAccept(buffer))
        {
            ExtendKds_ProcessMbox(buffer);
        }
        return ( event ^ EVENT_SYS_MBOX );
    }

	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
        EXTEND_KDS_LOG("ExtKds_Task sleep\r\n");
		OSAL_EventDelete(COMP_EXTEND_KDS, EVENT_EXTEND_KDS);
		Device_Disable(EXTEND_KDS_VHWL);
       	Device_Write(EXTEND_INT_VHWL, NULL, 0, PIN_MODE_INPUT_PULLUP); 
		return ( event ^ EVENT_SYS_SLEEP );
    }
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_EXTEND_KDS, ExtKds_Task, 0);

char import_kos_extend_kds;

